package org.tinygroup.uiml.engine;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.tinygroup.commons.tools.CollectionUtil;
import org.tinygroup.commons.tools.StringUtil;
import org.tinygroup.logger.LogLevel;
import org.tinygroup.logger.Logger;
import org.tinygroup.logger.LoggerFactory;
import org.tinygroup.uiml.UimlEngine;
import org.tinygroup.uiml.config.Component;
import org.tinygroup.uiml.config.Property;
import org.tinygroup.uiml.config.Style;
import org.tinygroup.uiml.config.Styles;
import org.tinygroup.uiml.metadata.ComponentType;
import org.tinygroup.uiml.metadata.PropertyType;
import org.tinygroup.uiml.metadata.StyleType;
import org.tinygroup.uiml.metadata.StylesType;

/**
 * Created by luoguo on 2014/7/3.
 */
public class UimlEngineDefault implements UimlEngine {
	private static UimlEngineDefault uimlEngineDefault = new UimlEngineDefault();
	
	/**
	 * key:所属name value:样式
	 */
	private Map<String,Style> styleMap = new HashMap<String,Style>();
	/**
	 * key:所属platform value:属生列表
	 */
	private Map<String, Map<String, StyleType>> styleTypeMap = new HashMap<String, Map<String, StyleType>>();
	/**
	 * key:组件id value:组件
	 */
	private Map<String, Component> componentMap = new HashMap<String, Component>();
	/**
	 * key:类型 value:组件类型列表
	 */
	private Map<String, Map<String, ComponentType>> componentTypeMap = new HashMap<String, Map<String, ComponentType>>();

	private Logger logger = LoggerFactory.getLogger(UimlEngineDefault.class);

	private UimlEngineDefault() {

	}

	public static UimlEngineDefault getInstance() {
		return uimlEngineDefault;
	}

	public void addComponent(Component component) {
		componentMap.put(component.getId(), component);
	}

	public void removeComponent(Component component) {
		componentMap.remove(component.getId());
	}

	public Component getComponent(String id) {
		return componentMap.get(id);
	}

	public void addComponentType(ComponentType componentType) {
		Map<String, ComponentType> platformMap = componentTypeMap
				.get(componentType.getType());
		if (platformMap == null) {
			platformMap = new HashMap<String, ComponentType>();
			componentTypeMap.put(componentType.getType(), platformMap);
		}
		platformMap.put(componentType.getPlatform(), componentType);
	}

	public void removeComponentType(ComponentType componentType) {
		Map<String, ComponentType> platformMap = componentTypeMap
				.get(componentType.getType());
		if (!CollectionUtil.isEmpty(platformMap)) {
			platformMap.remove(componentType.getPlatform());
			if (platformMap.size() == 0) {
				componentTypeMap.remove(componentType.getType());
			}
		}
	}

	public Map<String, ComponentType> getComponentTypeList(String type) {
		return componentTypeMap.get(type);
	}

	public ComponentType getComponentType(String type, String platform) {
		Map<String, ComponentType> typeMap = componentTypeMap.get(type);
		if (typeMap != null) {
			return typeMap.get(platform);
		}
		return null;
	}

	private void addPropertyTypeMap(String type, String platform,
			ComponentType platformContentType,
			Map<String, List<PropertyType>> propertyTypeMap) {
		if (platformContentType != null) {
			if (platformContentType.getExtendTypes() != null
					&& platformContentType.getExtendTypes().length() > 0) {
				// 如果有继承的类型
				String[] extendTypesArray = platformContentType
						.getExtendTypes().split(",");
				for (String extendType : extendTypesArray) {
					ComponentType baseExtendComponentType = getComponentType(
							extendType, "");// 某种类型下公有的组件类型
					addPropertyTypeMap(extendType, "", baseExtendComponentType,
							propertyTypeMap);
					if (!StringUtil.isBlank(platform)) {
						ComponentType extendComponentType = getComponentType(
								extendType, platform);// 某种类型下某种平台组件类型
						addPropertyTypeMap(extendType, platform,
								extendComponentType, propertyTypeMap);
					}
				}
			}
				// 如果存在对应平台的组件类型
				ComponentType baseComponentType = getComponentType(type, "");// 某种类型下公有的组件类型
				if(baseComponentType!=null){
					addPropertyTypeMap(platform, baseComponentType, propertyTypeMap);
				}
				addPropertyTypeMap(platform, platformContentType, propertyTypeMap);
		} else {
			logger.logMessage(LogLevel.WARN,
					"平台【platform:{0}】下的组件类型【type:{1}】不存在", platform, type);
		}
	}

	private void addPropertyTypeMap(String platform,
			ComponentType componentType,
			Map<String, List<PropertyType>> propertyTypeMap) {
			if (StringUtil.isBlank(platform)
					|| componentType.getPlatform().equals(platform)) {
				List<PropertyType> propertyTypes = componentType
						.getPropertyTypes();
				for (PropertyType propertyType : propertyTypes) {
					List<PropertyType> categoryList = propertyTypeMap
							.get(propertyType.getCategory());
					if (categoryList == null) {
						categoryList = new ArrayList<PropertyType>();
						propertyTypeMap.put(propertyType.getCategory(),
								categoryList);
					}
					if (!categoryList.contains(propertyType)) {
						categoryList.add(propertyType);
					}
				}
			}
	}

	public void addStylesType(StylesType styles) {
		Map<String, StyleType> platformStyleMap = styleTypeMap.get(getKey(styles
				.getPlatform()));
		if (platformStyleMap == null) {
			platformStyleMap = new HashMap<String, StyleType>();
			styleTypeMap.put(getKey(styles.getPlatform()), platformStyleMap);
		}
		for (StyleType style : styles.getStyles()) {
			platformStyleMap.put(style.getName(), style);
		}
	}

	public void removeStylesType(StylesType styles) {
		Map<String, StyleType> platformStyleMap = styleTypeMap.get(getKey(styles
				.getPlatform()));
		if (!CollectionUtil.isEmpty(platformStyleMap)) {
			for (StyleType styleType : styles.getStyles()) {
				platformStyleMap.remove(styleType.getName());
			}
			if (platformStyleMap.size() == 0) {
				styleTypeMap.remove(getKey(styles.getPlatform()));
			}
		}

	}

	private String getKey(String key) {
		if (key == null) {
			return "";
		}
		return key;
	}

	public StyleType getStyleType(String platform, String name) {
		Map<String, StyleType> platformStyleMap = styleTypeMap
				.get(getKey(platform));
		if (platformStyleMap != null) {
			return platformStyleMap.get(name);
		}
		return null;
	}

	public Collection<Component> getComponentList() {
		return componentMap.values();
	}

	public List<Property> getPropertyList(Component component, String platform) {
		List<Property> result = new ArrayList<Property>();
		getPropertyList(component, result, platform);
		return result;
	}

	private void getPropertyList(Component component, List<Property> result,
			String platform) {
		if (component.getRefId() != null && component.getRefId().length() > 0) {
			// 如果有引用ID，则直接返回引用ID对应组件的属性列表
			getPropertyList(getComponent(component.getRefId()), result,
					platform);
		} else {
			// 如果有继承组件，则添加继承来的的属性
			if (component.getExtendIds() != null) {
				String extendIds = component.getExtendIds();
				String[] extendArray = extendIds.split(",");
				for (String extendId : extendArray) {
					getPropertyList(getComponent(extendId), result, platform);
				}
			}
			if (component.getProperties() != null
					&& component.getProperties().getPropertyList() != null) {
				for (Property property : component.getProperties()
						.getPropertyList()) {
					// 如果是公共属性或者当前平台的属性，则添加之
					if (property.getPlatform() == null
							|| property.getPlatform().length() == 0
							|| property.getPlatform().equals(platform)) {
						if (checkPropertyExist(component.getType(),
								property.getName(), platform,
								property.getCategory())) {
							addPropertyToList(property, result);
						} else {
							logger.logMessage(
									LogLevel.WARN,
									"平台【platform:{0}】,分类【category:{1}】,组件类型【type:{2}】的属性【name:{3}】不存在",
									platform, property.getCategory(),
									component.getType(), property.getName());
						}
					}
				}
			}
		}
	}

	/**
	 * 检查对应的属性类型是否存在
	 * 
	 * @param type
	 * @param name
	 * @param platform
	 * @return
	 */
	private boolean checkPropertyExist(String type, String name,
			String platform, String category) {
		List<PropertyType> propertyTypes = getPropertyTypeListWithPlatform(
				type, platform).get(category);// TODO 从缓存中获取，不用每次遍历
		if (!CollectionUtil.isEmpty(propertyTypes)) {
			for (PropertyType propertyType : propertyTypes) {
				if (propertyType.getName().equals(name)) {
					return true;
				}
			}
		}
		return false;
	}

	private void addPropertyToList(Property property, List<Property> result) {
		// 如果不存在则添加之，如果已存在则覆盖原有的
		for (Property prop : result) {
			if (prop.getName().equals(property.getName())) {
				result.remove(prop);// 删除原有的
				break;
			}
		}
		result.add(property);// 新增最新的
	}

	public List<Property> getStylePropertyList(Component component,
			String platform) {
		List<Property> result = new ArrayList<Property>();
		getStylePropertyList(component, result, platform);
		return result;
	}

	private void getStylePropertyList(Component component,
			List<Property> result, String platform) {
		if (component.getRefId() != null && component.getRefId().length() > 0) {
			// 如果有引用ID，则直接返回引用ID对应组件的属性列表
			getStylePropertyList(getComponent(component.getRefId()), result,
					platform);
		} else {
			// 如果有继承组件，则添加继承来的的样式
			if (component.getExtendIds() != null) {
				String[] extendIdArray = component.getExtendIds().split(",");
				for (String extendId : extendIdArray) {
					getStylePropertyList(getComponent(extendId), result,
							platform);
				}
			}
			if (component.getStyles() != null) {
//				Styles styles = component.getStyles();
//				for (Style style : styles.getStyleList()) {
//					addStylePropertyList(component, style.getProperties(),
//							result, platform);
//				}
				String[] styleNameArray = component.getStyles().split(",");
				for(String styleName:styleNameArray){
					Style style = getStyle(styleName);
					if(style==null){
						logger.logMessage(
								LogLevel.WARN,
								"组件Id【id:{0}】,组件类型【type:{1}】的样式【name:{2}】不存在",
								component.getId(),component.getType(), styleName);
					   continue;
					}
					addStylePropertyList(component, style.getProperties(),result, platform);
				}
			}
			// 独有样式优先级最高
			addStylePropertyList(component, component.getUniqueStyle(), result,
					platform);
		}
	}

	private void addStylePropertyList(Component component,
			org.tinygroup.uiml.config.Properties properties,
			List<Property> result, String platform) {
		if (properties.getPropertyList() != null) {
			for (Property property : properties.getPropertyList()) {
				if (property.getPlatform() == null
						|| property.getPlatform().length() == 0
						|| property.getPlatform().equals(platform)) {
					if (checkPropertyExist(component.getType(),
							property.getName(), platform,
							property.getCategory())) {
						addPropertyToList(property, result);
					} else {
						logger.logMessage(
								LogLevel.WARN,
								"平台【platform:{0}】,分类【category:{1}】,组件类型【type:{2}】的属性【name:{3}】不存在",
								platform, property.getCategory(),
								component.getType(), property.getName());
					}
				}
			}
		}
	}

	public Map<String, List<PropertyType>> getPropertyTypeListWithPlatform(
			String type, String platform) {
		Map<String, List<PropertyType>> propertyTypeMap = new HashMap<String, List<PropertyType>>();
		Map<String, ComponentType> componentType = componentTypeMap
				.get(getKey(type));
		if (componentType != null) {
			// 如果能找到组件类型
			ComponentType platformContentType = componentType
					.get(getKey(platform));
			if (platformContentType != null) {
				ComponentType baseType = getComponentType(
						SUPER_COMPONENT_TYPE, "");
				if (baseType != null) {
					addPropertyTypeMap("", baseType, propertyTypeMap);
				}
				addPropertyTypeMap(type, platform, platformContentType,
						propertyTypeMap);
			}
		}
		return propertyTypeMap;
	}

	public Map<String, List<PropertyType>> getPropertyTypeListWithCategory(
			String type, String category) {
		Map<String, List<PropertyType>> propertyTypeMap = new HashMap<String, List<PropertyType>>();
		Map<String, ComponentType> components = componentTypeMap.get(getKey(type));
		if (components != null) {
			for (ComponentType componentType : components.values()) {
				ComponentType baseType = getComponentType(SUPER_COMPONENT_TYPE, "");
				if (baseType != null) {
					addPropertyTypeMapWithCategory(category,componentType.getPlatform(), baseType, propertyTypeMap);
				}
				addPropertyTypeCategoryMap(type, category,componentType.getPlatform(),componentType, propertyTypeMap);
				
			}
		
		}
		return propertyTypeMap;
	}

	private void addPropertyTypeCategoryMap(String type, String category,String platform,ComponentType componentType,
			Map<String, List<PropertyType>> propertyTypeMap) {
		    if(componentType!=null){
		    	if (componentType.getExtendTypes() != null
						&& componentType.getExtendTypes().length() > 0) {
					// 如果有继承的类型
					String[] extendTypesArray = componentType.getExtendTypes()
							.split(",");
					for (String extendType : extendTypesArray) {
						ComponentType baseExtendComponentType = getComponentType(
								extendType, "");// 某种类型下公有的组件类型
						addPropertyTypeCategoryMap(extendType,category, platform, baseExtendComponentType,
								propertyTypeMap);
						if (!StringUtil.isBlank(platform)) {
							ComponentType extendComponentType = getComponentType(
									extendType, platform);// 某种类型下某种平台组件类型
							addPropertyTypeCategoryMap(extendType,category, platform,
									extendComponentType, propertyTypeMap);
						}
					}
				}
		    	addPropertyTypeMapWithCategory(category,platform,componentType,propertyTypeMap);
		    }
	}

	private void addPropertyTypeMapWithCategory(String category,
			String platform, ComponentType componentType,
			Map<String, List<PropertyType>> propertyTypeMap) {
		if (componentType != null) {
			List<PropertyType> platformList = propertyTypeMap.get(platform);
			if (platformList == null) {
				platformList = new ArrayList<PropertyType>();
				propertyTypeMap.put(platform, platformList);
			}
			List<PropertyType> propertyTypes = componentType.getPropertyTypes();
			for (PropertyType propertyType : propertyTypes) {
				if (propertyType.getCategory().equals(category)) {
					if (!platformList.contains(propertyType)) {
						platformList.add(propertyType);
					}
				}
			}
		}
	}

	public void addStyle(Style style) {
		styleMap.put(style.getName(), style);
	}

	public void removeStyle(Style style) {
		styleMap.remove(style.getName());
	}
	
	public void addStyle(Styles styles) {
	   if(styles.getStyleList()!=null){
		  for(Style style:styles.getStyleList()){ 
			  addStyle(style); 
		  }
	   }
	}

	public void removeStyle(Styles styles) {
		if(styles.getStyleList()!=null){
		   for(Style style:styles.getStyleList()){ 
			  removeStyle(style); 
		   }
		}
	}

	public Style getStyle(String name) {
		return styleMap.get(name);
	}

}
